package com.qizhidao.j2cache.config;


import com.qizhidao.j2cache.redis.J2CacheTemplate;
import com.qizhidao.j2cache.redis.RedisProperties;
import net.oschina.j2cache.CacheChannel;
import net.oschina.j2cache.J2CacheBuilder;
import net.oschina.j2cache.J2CacheConfig;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

@Configuration
@EnableConfigurationProperties({L1CacheProperties.class, RedisProperties.class})
public class CacheConfiguration {

    protected String region = "default";

    @Bean(value = "l1cacheProperties")
    public Properties l1cacheProperties(L1CacheProperties propertiesL1) throws IOException {
        Properties properties = new Properties();
        String provider_class = propertiesL1.getProperty("provider_class", propertiesL1.getProvider_class());
        InputStream is;
        if ("caffeine".equals(provider_class)) {
            is = Thread.currentThread().getContextClassLoader().getResourceAsStream("caffeine.properties");
            properties.load(is);
        }
        properties.put("j2cache.L1.provider_class", provider_class);
        return properties;
    }

    @Bean(value = "j2cacheProperties")
    public Properties l2cacheProperties(Properties l1cacheProperties, RedisProperties propertiesL2, Environment environment) throws IOException {
        if (propertiesL2.size() == 0 || StringUtils.isEmpty(propertiesL2.getProperty("hosts"))) {
            //如果未配置j2cache二级缓存配置，取spring.redis配置
            String host = environment.getProperty("spring.redis.host", "127.0.0.1");
            String port = environment.getProperty("spring.redis.port", "6379");
            String password = environment.getProperty("spring.redis.password");
            propertiesL2.setProperty("hosts", host + ":" + port);
            if (!StringUtils.isEmpty(password)) {
                propertiesL2.setProperty("password", password);
            }
            propertiesL2.setProperty("database", environment.getProperty("spring.redis.database", "0"));
            propertiesL2.setProperty("ssl", environment.getProperty("spring.redis.ssl", "false"));
            propertiesL2.setProperty("timeout", environment.getProperty("spring.redis.timeout", "3000"));
        }
        Properties j2cacheProperties = new Properties();
        j2cacheProperties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("j2cache.properties"));
        j2cacheProperties.putAll(addPrefix(propertiesL2, "redis."));
        j2cacheProperties.putAll(l1cacheProperties);
        j2cacheProperties.put("j2cache.L2.provider_class", "redis");
        String region = propertiesL2.getRegion();
        if (StringUtils.isEmpty(region)) {
            region = System.getProperty("project.name");
            if (StringUtils.isEmpty(region)) {
                region = environment.getProperty("spring.application.name", "default");
            }
        }
        this.region = region;
        return j2cacheProperties;
    }

    @Bean
    public CacheChannel initJ2Cache(Properties j2cacheProperties) {
        J2CacheConfig config = J2CacheConfig.initFromConfig(j2cacheProperties);
        //不使用集群通知
//        config.setBroadcast("none");
        J2CacheBuilder builder = J2CacheBuilder.init(config);
        return builder.getChannel();
    }

    @Bean
    public J2CacheTemplate j2CacheTemplate(CacheChannel channel, RedisConnectionFactory redisConnectionFactory) {
        return new J2CacheTemplate(redisConnectionFactory, channel, this.region);
    }


    private static Properties addPrefix(Properties properties, String prefix) {
        if (properties == null)
            return null;

        Properties result = new Properties();
        Iterator<Map.Entry<Object, Object>> it = properties.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<Object, Object> entry = it.next();
            if (entry.getKey().toString().startsWith(prefix)) {
                result.put(entry.getKey(), entry.getValue());
            } else {
                result.put(prefix + entry.getKey().toString(), entry.getValue());
            }
        }
        return result;
    }
}
